package auto_mqtt

import (
	"encoding/json"
	"fmt"
	"regexp"
	"server/global"
	"server/global/mqtt/fsc"
	"server/model"
	"server/service"
	"server/utils"
	"strconv"
	"time"

	MQTT "github.com/eclipse/paho.mqtt.golang"
	"go.uber.org/zap"
)

type Client struct {
	MQTT.Client
	Host     string
	ClientID string
	UserName string
	Password string
}

type Message struct {
	ClientID string `json:"clientId"`
	Type     string `json:"type"`
	Data     string `json:"data,omitempty"`
	Time     int64  `json:"time"`
}

var messageHandler MQTT.MessageHandler

// var messageHandler MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
func (m *Client) mMessageHander(client MQTT.Client, msg MQTT.Message) {
	// global.LOG.Info("lock mqtt message",
	// 	zap.Any("topic", msg.Topic()),
	// 	zap.Any("message", string(msg.Payload())),
	// )
	// 匹配设备上传信息
	reg_tx, err := regexp.Compile(`^fsc/(.*?)/(.*?)/tx`)
	if err != nil {
		global.LOG.Error(fmt.Sprintf("%v", err))
		return
	}
	if reg_tx.MatchString(msg.Topic()) == true {
		result := reg_tx.FindStringSubmatch(msg.Topic())
		sn := result[2]
		// 转换数据为json
		var data AswData
		err := json.Unmarshal([]byte(msg.Payload()), &data)
		if err != nil {
			global.LOG.Error("topic",
				zap.Any("topic", msg.Topic()),
				zap.Any("payload", []byte(msg.Payload())),
				zap.Any("err", err),
			)
			return
		}
		err = m.DeviceStatusDeal(sn, data)
		if err != nil {
			global.LOG.Error(fmt.Sprintf("%v", err))
			return
		} else {
			err = m.DeviceAutoControl(sn)
			if err != nil {
				global.LOG.Error(fmt.Sprintf("%v", err))
			}
		}
	}
}

type AswData struct {
	AswCode string `json:"aswcode"`
	AswMsg  string `json:"aswmsg"`
}

// 设备状态变化处理
func (m *Client) DeviceStatusDeal(sn string, data AswData) error {
	// 根据sn查询设备信息
	d := &model.Device{Sn: sn}
	exist, _ := service.DeviceExistBySn(*d)
	if !exist {
		// return errors.New(fmt.Sprintf("[%v]设备不存在, 无法更新设备状态~", sn))
		return nil
	}
	device, err := service.DeviceGetBySn(*d)
	if err != nil {
		return err
	}
	if device.Tag == "infrared" {
		// fmt.Println("红外变化")
		if data.AswCode == fsc.CODE_INFRARED_GET_PEOPLE {
			if aswmsg, err_msg := strconv.Atoi(data.AswMsg); err_msg == nil {
				// global.LOG.Debug(fmt.Sprintf("红外变化[%v]: %v", sn, data.AswMsg))
				// 修改状态
				device.Status = aswmsg
				err = service.DeviceEdit(*device)
				if err != nil {
					return err
				}
				// 添加记录
				dlog := &model.DeviceLog{DeviceID: device.ID, Status: aswmsg, Value: ""}
				err = service.DeviceLogAdd(*dlog)
				if err != nil {
					return err
				}
			}
		}
	}
	if device.Tag == "door" {
		// fmt.Println("门禁变化")
		if data.AswCode == fsc.CODE_DOOR_GET_DOOR {
			if aswmsg, err_msg := strconv.Atoi(data.AswMsg); err_msg == nil {
				// global.LOG.Debug(fmt.Sprintf("门禁变化[%v]: %v", sn, data.AswMsg))
				// 修改状态
				device.Status = aswmsg
				err = service.DeviceEdit(*device)
				if err != nil {
					return err
				}
				// 添加记录
				dlog := &model.DeviceLog{DeviceID: device.ID, Status: aswmsg, Value: ""}
				err = service.DeviceLogAdd(*dlog)
				if err != nil {
					return err
				}
			}
		}
	}
	if device.Tag == "switch" {
		// fmt.Println("源控变化")
		if data.AswCode == fsc.CODE_SWITCH_GET_SWITCH {
			if aswmsg, err_msg := strconv.Atoi(data.AswMsg); err_msg == nil {
				// global.LOG.Debug(fmt.Sprintf("源控变化[%v]: %v", sn, data.AswMsg))
				// 修改状态
				device.Status = aswmsg
				err = service.DeviceEdit(*device)
				if err != nil {
					return err
				}
				// 添加记录
				dlog := &model.DeviceLog{DeviceID: device.ID, Status: aswmsg, Value: ""}
				err = service.DeviceLogAdd(*dlog)
				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}

type AutoCondition struct {
	Sn     string `json:"sn"`
	Status int    `json:"status"`
}
type AutoRun struct {
	Sn     string `json:"sn"`
	Status int    `json:"status"`
}

func (m *Client) DeviceAutoControlRun(runs []AutoRun) error {
	for _, r := range runs {
		device, err := service.DeviceGetBySn(model.Device{Sn: r.Sn})
		if err != nil {
			return err
		}
		if device.ID > 0 && device.Online == 1 {
			// 开关设备
			if device.Tag == "switch" {
				if r.Status == 1 {
					// global.LOG.Info(fmt.Sprintf("开关[%v]->开", device.Sn))
					m.Publish(device.Sub, 0, false, fmt.Sprintf(`{"code":"%v"}`, fsc.CODE_SWITCH_SET_OPEN))
				}
				if r.Status == 0 {
					// global.LOG.Info(fmt.Sprintf("开关[%v]->关", device.Sn))
					m.Publish(device.Sub, 0, false, fmt.Sprintf(`{"code":"%v"}`, fsc.CODE_SWITCH_SET_CLOSE))
				}
			}
		}
	}
	return nil
}

func (m *Client) DeviceAutoControl(sn string) error {
	// 查询包含设备sn的智能场景
	autos, err := service.AutoGetEnableBySn(sn)
	if err != nil {
		return err
	}
	for _, a := range autos {
		// condition
		var conditions []AutoCondition
		err = json.Unmarshal([]byte(a.Condition), &conditions)
		if err != nil {
			return err
		}
		// run
		var runs []AutoRun
		err = json.Unmarshal([]byte(a.Run), &runs)
		if err != nil {
			return err
		}
		is_run := false
		// ‘与’ 条件执行任务
		if a.Logic == "and" {
			for _, c := range conditions {
				is_run = true
				device, err := service.DeviceGetBySn(model.Device{Sn: c.Sn})
				if err != nil {
					return err
				}
				// 设备存在
				if device.ID > 0 {
					// 设备掉线, 不执行动作
					if device.Online == 0 {
						is_run = false
						break
					}
					// 当前设备条件不满足, 不执行动作
					if device.Status != c.Status {
						is_run = false
						break
					}
				} else { // 设备不存在，不执行动作
					is_run = false
					break
				}
			}
		}
		// ‘或’ 条件执行任务
		if a.Logic == "or" {
			for _, c := range conditions {
				device, err := service.DeviceGetBySn(model.Device{Sn: c.Sn})
				if err != nil {
					return err
				}
				// 设备存在、 在线、 满足条件,执行动作
				if device.ID > 0 && device.Online == 1 && device.Status == c.Status {
					is_run = true
					break
				}
			}
		}
		// 是否要执行任务
		if is_run {
			go m.DeviceAutoControlRun(runs)
		}
	}
	return nil
}

func (m *Client) NewClient() {
	ClientID := "server-auto-" + utils.GenerateTimeMD5()[0:8]
	opts := MQTT.NewClientOptions()
	opts.AddBroker(global.CONFIG.Emqx.Host)
	opts.SetClientID(ClientID)
	opts.SetUsername(global.CONFIG.Emqx.Username)
	opts.SetPassword(global.CONFIG.Emqx.Password)
	opts.SetCleanSession(true)
	opts.SetAutoReconnect(true)
	opts.SetKeepAlive(120 * time.Second)
	opts.SetPingTimeout(10 * time.Second)
	opts.SetWriteTimeout(10 * time.Second)
	opts.SetOnConnectHandler(func(client MQTT.Client) {
		messageHandler = m.mMessageHander
		// 连接被建立后的回调函数
		global.LOG.Info(fmt.Sprintf(" Mqtt is connected! clientId: %v", ClientID))
		// 重连后重新订阅
		m.Subscribe()
	})
	opts.SetConnectionLostHandler(func(client MQTT.Client, err error) {
		// 连接被关闭后的回调函数
		global.LOG.Info(fmt.Sprintf("Mqtt is disconnected! clientId: %v reason: %v", ClientID, err.Error()))
	})

	m.Client = MQTT.NewClient(opts)
}

func (m *Client) Connect() {
	global.LOG.Info("connect")

	token := m.Client.Connect()
	if token.Wait() && token.Error() != nil {
		global.LOG.Error(fmt.Sprintf("%v", token.Error()))
	}
}

func (m *Client) DisConnect() {
	fmt.Println("disconnect")
	m.Client.Disconnect(250)
}

func (m *Client) Subscribe() {
	global.LOG.Info("subscribe")
	topics := make(map[string]byte)
	// topics["fsc/+/+/tx"] = 0
	for _, v := range global.CONFIG.Emqx.AutoTopics {
		topics[v] = 0
	}
	global.LOG.Info(fmt.Sprintf("%v", topics))
	// token := m.Client.Subscribe("dqt201/+/tx", 0, messageHandler)
	token := m.Client.SubscribeMultiple(topics, messageHandler)
	if token.Wait() && token.Error() != nil {
		global.LOG.Error(fmt.Sprintf("%v", token.Error()))
	}
}

func (m *Client) Pub() {
	global.LOG.Info("publish")
	s := time.Now().String()
	token := m.Client.Publish("date", 0, false, s)
	if token.Wait() && token.Error() != nil {
		global.LOG.Error(fmt.Sprintf("%v", token.Error()))
	}
}

func (m *Client) Run() {

	m.NewClient()
	m.Connect()

	// var wg sync.WaitGroup
	// go func() {
	// 	for {
	// 		time.Sleep(time.Millisecond * 100)
	// 		m.job_check_lock()
	// 	}
	// }()
	// wg.Add(1)
	// go m.job_check_lock()
	// 定义一个cron运行器
	// c := cron.New()
	// c.AddFunc("*/1 * * * * *", m.job_check_lock)
	// c.Start()
}
